디폴트 알고리즘으로 원하는 결과가 안나올 때
— 1 min read
(elasticsearch 7.10 기준으로 작성)
elasticsearch는 흔히 로그 분석/관리 시스템이나 full-text search용도로 쓰인다. 하지만 지난번 + 이번에 내가 맡은 프로젝트에서는 full-text search가 필요없는 컨텐츠에 대한 검색엔진 용도로 elasticsearch를 사용했다. 이를테면 A필드가 매칭되는게 1순위, 없으면 B필드가 매칭되는게 2순위...
와 같은 여러 개의 조건들을 충족시키는 결과를 찾는 것이다. 내가 작성한 쿼리 조건에 매칭되는지 아닌지가 중요하고 document가 검색 키워드를 몇개나 가지고 있는지 등등은 중요하지 않았다. 그런데 기본 알고리즘이 적용되다보니 tf, idf 등의 점수때문에 완전히 A, B 필드에 대한 score 순으로 정렬되지는 않았다. 이런 상황에서 필요한 것이 similarity(유사도, scoring algorithm) 를 설정하는 것이다.
어떤 document를 높은 순위로 결과를 뽑을 것인지에 대해 elasticsearch는 기본적으로 Okapi BM25 알고리즘 (과거에는 TF/IDF) 을 사용하여 score를 계산한다. 이 score를 1순위로 해서 정렬한 결과를 리턴하는게 디폴트다. 여기서 쓰이는 알고리즘을 similarity 설정으로 변경할 수 있다.
공식 문서를 보면 별도 설정 없이 선택할 수 있는 디폴트 알고리즘은 3개이다.
디폴트 알고리즘은 키워드가 문서에서 얼마나 자주 나타나는지, 모든 문서에서 자주 등장하는지 특정 문서에서만 자주 등장하는지 등을 계산하여 키워드의 중요도에 따른 검색결과를 뽑아내는데 최적화되어있다. 이런 파라미터들이 완전히 무시되어도 괜찮다면 boolean으로 similarity를 변경하면 된다.
커스텀하게 파라미터를 튜닝하거나 스크립트를 짜서 similarity를 정의하고 필요한 필드에 적용해서 사용할 수 수도 있다. 지난 프로젝트 때는 가장 마지막 정렬 순위로 tf를 반영해야하는 요구사항이 있어서 이 방식을 썼다.
elasticsearch 제공 similarity
type에 type name이 들어가고 다른 option들은 type에 따라서 알고리즘 공식에 들어가는 parameter의 값들을 넣어줄 수 있다. (가능한 type과 옵션은 공식문서 참조)
1## 예시 - DFR similarity일때23PUT /index4{5 "settings": {6 "index": {7 "similarity": {8 "my_similarity": {9 "type": "DFR",10 "basic_model": "g",11 "after_effect": "l",12 "normalization": "h2",13 "normalization.h2.c": "3.0"14 }15 }16 }17 }18}
위 예시에서 정의한 my_similarity를 indexing할 때 필드 매핑하는 부분에서 넣어주면 해당 필드에만 적용이 된다.
1"mappings": {2 "properties": {3 "my_field": {4 "type": "text",5 "similarity": "my_similarity"6 }7 }8 }
디폴트 알고리즘인 BM25에도 파라미터를 바꿔서 변경을 줄 수 있다.
Scripted similarity
알고리즘 통째로 내가 script를 짤 수도 있다. 잘 모른다면 다소 위험한 방식일 수 있고 지켜야하는 rule도 있다.
그럼에도 idf 영향을 없애고 tf만 남겨두고싶어서 썼다. 기본 bm25 알고리즘을 조금 변형했다.
1double tf = Math.sqrt(doc.freq); return query.boost * tf
TODO: constant score query를 뒤늦게 발견했는데, boolean similarity 적용하는 것과 비슷해보이는데 좀더 알아봐야 할 듯 하다.
https://www.elastic.co/guide/en/elasticsearch/reference/current/similarity.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-similarity.html
https://saskia-vola.com/when-simple-is-better-the-boolean-similarity-module